import json
import logging
import os
import traceback
from typing import List, Optional

import git
import google.protobuf.json_format as json_format

import coin.proto.options_pricing_pb2 as op_pb2
import coin2.service.research.options_service_pb2 as os_pb2
from coin.base.datetime_util import to_datetime
from coin.exchange.base.kr_rest.py_product import PyProduct
from coin.proto.options_pricing_pb2 import SabrPricingParamsProto
from coin.support.options_pricing.types import PricingParamsType
from xunkemgmt_client.client.api_client import XunkemgmtClient


def query_sabr_pricing_params(product: PyProduct
) -> Optional[SabrPricingParamsProto]:
  assert product.market_name == 'Options', product.market_name
  git_root = git.Repo(os.getcwd(), search_parent_directories=True).git.rev_parse(
      '--show-toplevel')
  pricing_params_file = os.path.join(
      git_root, '../coin_deploy/options_pricing/sabr.json')
  pricing_param = None
  with open(pricing_params_file) as f:
    for elem in json.load(f):
      pricing_proto = SabrPricingParamsProto()
      json_format.ParseDict(elem, pricing_proto)
      expiry_date = to_datetime(pricing_proto.expiry_time)
      if pricing_proto.exchange == product.exchange_name and \
         pricing_proto.base == product.base.currency and \
         pricing_proto.quote == product.quote.currency and \
         expiry_date.strftime('%Y%m%d') == product.expiry_str:
        pricing_param = pricing_proto
        break
  return pricing_param


def query_options_pricing_params(models: List[PricingParamsType],
                                 *,
                                 from_local: bool=False,
) -> PricingParamsType:
  pricing_params = {}
  if from_local:
    git_root = git.Repo(os.getcwd(), search_parent_directories=True).git.rev_parse(
        '--show-toplevel')
    for model in models:
      if model == op_pb2.SABR:
        sabr_params = []
        pricing_params_file = os.path.join(
            git_root, '../coin_deploy/options_pricing/sabr.json')
        with open(pricing_params_file) as f:
          sabr_proto = op_pb2.SabrPricingParamsProto()
          for elem in json.load(f):
            json_format.ParseDict(elem, sabr_proto)
            sabr_params.append(op_pb2.OptionsPricingParamsProto(
                model=model,
                sabr=sabr_proto,))
        pricing_params[model] = sabr_params
  else:
    with XunkemgmtClient() as client:
      for model in models:
        try:
          rsp = client.query_options_pricing_params_snapshots(
              os_pb2.QueryOptionsPricingParamsSnapshotsRequestProto(model=model))
          pricing_params[model] = rsp.pricing_params
        except Exception:
          logging.error(traceback.format_exc())
  return pricing_params
